/*
 * @Author: 李石
 * @Date: 2024-05-22 10:55:25
 * @LastEditors: lishi
 * @LastEditTime: 2024-05-22 11:57:46
 * @Description: 
 * Copyright (c) 2024 by ${lishi0105@163.com}, All Rights Reserved. 
 */
#include <memory>
#include "TimerUtil.hpp"

TimerUtil::TimerUtil(size_t maxThreads) 
    : timer_fd(-1), running(false), activeTasks(0), maxThreads(maxThreads) {
    timer_fd = timerfd_create(CLOCK_REALTIME, 0);
    if (timer_fd == -1) {
        perror("timerfd_create");
        throw std::runtime_error("Failed to create timerfd");
    }
    if(maxThreads == 0 || maxThreads > 100) {
        maxThreads = 2;
    }
    threadPool = std::make_unique<ThreadPool>(maxThreads);
}

TimerUtil::~TimerUtil() {
    stop();
    close(timer_fd);
    std::cout << "TimerUtil destruct" << std::endl;
}

void TimerUtil::start(int initial_usec, int interval_usec, TimerCallback callback) {
    if (running.load()) {
        stop();
    }

    this->callback = callback;

    struct itimerspec new_value;
    new_value.it_value.tv_sec = initial_usec / 1000000;
    new_value.it_value.tv_nsec = (initial_usec % 1000000) * 1000;
    new_value.it_interval.tv_sec = interval_usec / 1000000;
    new_value.it_interval.tv_nsec = (interval_usec % 1000000) * 1000;

    if (timerfd_settime(timer_fd, 0, &new_value, nullptr) == -1) {
        perror("timerfd_settime");
        throw std::runtime_error("Failed to set timer");
    }

    running.store(true);
    timer_thread = std::thread(&TimerUtil::run, this);
}

void TimerUtil::stop() {
    if (running.load()) {
        running.store(false);
        if (timer_thread.joinable()) {
            timer_thread.join();
        }
    }
}

void TimerUtil::run() {
    struct pollfd fds;
    fds.fd = timer_fd;
    fds.events = POLLIN;

    while (running.load()) {
        int ret = poll(&fds, 1, 1000);
        if (ret > 0 && (fds.revents & POLLIN)) {
            uint64_t expirations;
            ssize_t s = read(timer_fd, &expirations, sizeof(expirations));
            if (s != sizeof(expirations)) {
                perror("read");
                continue;
            }
            if (callback) {
                if (activeTasks.load() >= maxThreads) {
                    std::cerr << "Warning: Maximum number of active tasks reached. Skipping callback." << std::endl;
                } else {
                    activeTasks.fetch_add(1);
                    threadPool->enqueue([this]() {
                        callback();
                        activeTasks.fetch_sub(1);
                    });
                }
            }
        }
    }
}
